package com.jvyou.framework.handler.exception;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.jvyou.common.core.domain.model.Result;
import com.jvyou.common.enums.result.ErrorShowType;
import com.jvyou.common.enums.result.HttpCodeEnum;
import com.jvyou.common.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.BindingException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.sql.SQLException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author 橘柚
 * @version 1.0-SNAPSHOT
 * @Date 2023/2/4 1:10
 * @Description 全局异常拦截器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {


    /**
     * 数据库语句错误
     */
    @ExceptionHandler(BadSqlGrammarException.class)
    public Result<String> sqlException(Exception e) {
        String message = e.getMessage();
        String[] split = message.split("###");
        split = split[2].replace("]", "").split("\\\\");
        String xml = split[split.length - 1].replace("\n", "");
        String sql = message.split("### Cause: ")[0].split("### SQL: ")[1].replace("\n", "");
        while (sql.contains("  ")) {
            sql = sql.replace("  ", " ");
        }
        log.error("==========================");
        log.error("SQL语句发生错误");
        log.error("xml: {}", xml);
        log.error("sql：{}", sql);
        log.error("==========================");
        return Result.error(HttpCodeEnum.SYSTEM_ERROR.getCode(), "数据库语句错误", ErrorShowType.NOTIFICATION);
    }

    /**
     * 数据库语句错误
     */
    @ExceptionHandler({SQLException.class, BindingException.class})
    public Result<String> handleSQLException(Exception e) {
        String message = e.getMessage();
        log.error("数据库语句错误，异常信息:", e);
        if (message.contains("Duplicate entry")) {
            Pattern pattern = Pattern.compile("'([^']+)'");
            Matcher matcher = pattern.matcher(message);
            String data = matcher.find() ? matcher.group(1) : "-";
            message = "已存在该数据（" + data + "），请修改后重试！";
            return Result.error(HttpCodeEnum.ADD_FAIL.getCode(), message, ErrorShowType.NOTIFICATION);
        } else if (message.contains("Data too long")) {
            message = "数据长度过长，请修改后重试！";
            return Result.error(HttpCodeEnum.ADD_FAIL.getCode(), message, ErrorShowType.NOTIFICATION);
        } else if (message.contains("doesn't have a default value")) {
            Pattern pattern = Pattern.compile("'([^']+)'");
            Matcher matcher = pattern.matcher(message);
            String field = matcher.find() ? matcher.group(1) : "-";
            message = field + " 数据不能为空，请修改后重试！";
        }
        return Result.error(HttpCodeEnum.SYSTEM_ERROR.getCode(), message, ErrorShowType.NOTIFICATION);
    }

    /**
     * 未登录异常
     *
     * @return 响应结果
     */
    @ExceptionHandler(NotLoginException.class)
    public Result<Boolean> handlerNotLoginException(NotLoginException notLoginException) {
        String message = notLoginException.getMessage();
        log.error("登录检验异常，异常信息:{}", message);
        if (message.contains("无效")) {
            message = "无效的登录信息，请重新登录！";
        } else if (message.contains("未能读取到有效")) {
            message = "请登陆后操作";
        }
        return Result.error(HttpCodeEnum.REQUIRE_TOKEN, message);
    }

    /**
     * 没有角色异常
     *
     * @return 响应结果
     */
    @ExceptionHandler(NotRoleException.class)
    public Result<Boolean> handlerNotRoleException(NotRoleException notLoginException) {
        return Result.error(HttpCodeEnum.NO_OPERATOR_AUTH, "权限不足");
    }

    /**
     * 无权限
     *
     * @return 响应结果
     */
    @ExceptionHandler(NotPermissionException.class)
    public Result<Boolean> handlerNotPermissionException(NotPermissionException notLoginException) {
        return Result.error(HttpCodeEnum.NO_OPERATOR_AUTH);
    }

    /**
     * 系统业务异常
     *
     * @return 响应结果
     */
    @ExceptionHandler(AppException.class)
    public Result<Boolean> handlerSystemException(AppException systemException) {
        return Result.error(systemException.getCode(), systemException.getMsg(), systemException.getShowType());
    }

    /**
     * 处理请求体为空异常
     *
     * @return 响应结果
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<Boolean> handleHttpMessageNotReadableException(Exception e) {
        log.error("请求体异常", e);
        return Result.error(HttpCodeEnum.CLIENT_ERROR);
    }

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public Result<Boolean> handleFileSizeLimitExceeded(MaxUploadSizeExceededException e, RedirectAttributes redirectAttributes) {
        return Result.error(HttpCodeEnum.FILE_SIZE_ERROR);
    }

    /**
     * 处理参数校验异常
     *
     * @param e 参数校验异常
     * @return 响应结果
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Boolean> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("参数校验异常", e);
        String errorMsg = e.getBindingResult()
                .getAllErrors()
                .get(0)
                .getDefaultMessage();
        return Result.error(HttpCodeEnum.ARGUMENT_VALID_ERROR, errorMsg);
    }

    /**
     * 空指针异常
     */
    @ExceptionHandler(NullPointerException.class)
    public Result<Boolean> nullPointerException(NullPointerException e) {
        log.error("空指针异常", e);
        return Result.error(HttpCodeEnum.SYSTEM_ERROR, "空指针异常");
    }
}
